<?php

class Model_Mapper_Locations {
	
	protected $_dbTable;
	private static $instance;
	
	public static function newInstance() {
		if (! self::$instance instanceof self) {
			self::$instance = new self ();
		}
		return self::$instance;
	}
	
	public function setDbTable($dbTable) {
		if (is_string ( $dbTable )) {
			$dbTable = new $dbTable ();
		}
		if (! $dbTable instanceof Zend_Db_Table_Abstract) {
			throw new Exception ( 'Invalid table data gateway provided' );
		}
		$this->_dbTable = $dbTable;
		return $this;
	}
	
	public function getDbTable() {
		if (null === $this->_dbTable) {
			$this->setDbTable ( 'Model_Table_Locations' );
		}
		return $this->_dbTable;
	}
	
	/*
	 * ********************************************
	 * Get Top Level Locations means parent_id=0
	 * ********************************************
	 */
	
	function getTopLocations($enabled = false, $array = false) {
		$args = array ('parent_id' => 0 );
		if ($enabled) {
			$args ['enabled'] = 1;
		}
		if ($array) {
			return $this->getByCondition ( $args, true );
		}
		return $this->getByCondition ( $args );
	}
	
	/*
	 * ***************************************************************
	 * Get Childrens of location either immedate or all recursively
	 * ***************************************************************
	 */
	
	function getChildrens($location, $recursive = false) {
		if ($location == '') {
			throw new Exception ( 'Invalid Category Provided.' );
		}
		$location_id = '';
		if ($location instanceof Model_Categories) {
			$location_id = $location->getLocation_id ();
		} else {
			$location_id = $location;
		}
		
		if ($recursive) {
			
			$items = array ();
			$subs = $this->_getChildrens ( $location_id, true );
			
			foreach ( $subs as $cat ) {
				$items [] = $cat;
				
				$temp = $this->getChildrens ( $cat ['location_id'], true );
				if ($temp) {
					$items = array_merge ( $items, $temp );
				}
			
			}
			
			return $items;
		} else {
			return $this->_getChildrens ( $location_id, true );
		}
	}
	
	/*
	 * ***********************************************
	 * Check if location has childrens
	 * ***********************************************
	 */
	
	function hasChildrens($location) {
		if ($location == '') {
			throw new Exception ( 'Invalid Category Provided.' );
		}
		
		if (! $location instanceof Model_Locations) {
			$location = Model_Mapper_Locations::newInstance ()->getByID ( $location );
		}
		
		$items = $this->_getChildrens ( $location, true );
		if (count ( $items ) > 0) {
			return true;
		}
		return false;
	
	}
	
	/*
	 * ****************************************************
	 * Internal Function to get children of a location
	 * ****************************************************
	 */
	
	private function _getChildrens($location, $array = false) {
		if ($location == '') {
			throw new Exception ( 'Invalid Category Provided.' );
		}
		$location_id = '';
		if ($location instanceof Model_Locations) {
			$location_id = $location->getLocation_id ();
		} else {
			$location_id = $location;
		}
		if ($array) {
			$args = array ('parent_id' => $location_id );
			return $this->getByCondition ( $args, true );
		} else {
			$args = array ('parent_id' => $location_id );
			return $this->getByCondition ( $args, false );
		}
	
	}
	
	/*
	 * *******************************************
	 * Gets Location By Slug
	 * *******************************************
	 */
	
	function getBySlug($slug, $enabled = false) {
		$table = $this->getDbTable ();
		$select = $table->select ();
		$select->from ( $table );
		$select->where ( 'slug=?', $slug );
		if ($enabled) {
			$select->where ( 'enabled=?', 1 );
		}
		$result = $this->extend ( $table->fetchAll ( $select ) );
		if ($result) {
			return $result [0];
		} else {
			return array ();
		}
	
	}
	
	/*
	 * **********************************************
	 * Find locations using like operater
	 * **********************************************
	 */
	public function find($query) {
		if ($query == '') {
			throw new Exception ( 'Invalid QUERY provided' );
		}
		$table = $this->getDbTable ();
		$select = $table->select ();
		$select->where ( $query );
		$select->from ( $table );
		$result = $this->extend ( $table->fetchAll ( $select ) );
		if ($result) {
			return $result;
		}
		return array ();
	
	}
	
	/*
	 * ****************************************************
	 * Gets Location by specified condition given in array
	 * ****************************************************
	 */
	
	function getByCondition(array $args, $array = false) {
		if (! is_array ( $args )) {
			throw new Exception ( 'Invalid Argument Array Provided' );
		}
		$table = $this->getDbTable ();
		$select = $table->select ();
		$select->from ( $table );
		foreach ( $args as $key => $value ) {
			$select->where ( $key . '=?', $value );
		}
		
		$result = $table->fetchAll ( $select );
		$result = $this->extend ( $result );
		if ($result) {
			if ($array) {
				//echo 'array requested';
				foreach ( $result as $key => $item ) {
					$result [$key] = $item->toArray ();
				}
			}
			//print_r($result);
			return $result;
		
		} else {
			return array ();
		}
	}
	
	/*
	 * ********************************************
	 * Gets whole tree of all lcoations
	 * ********************************************
	 */
	
	public function tree() {
		$all = $this->getTopLocations ();
		$items = array ();
		if ($all) {
			foreach ( $all as $location ) {
				$items [] = $this->_toTree ( $location->getLocation_id (), 0 );
			}
		}
		
		return $items;
	}
	
	/*
	 * *******************************************
	 * Retrieves the whole tree of given location
	 * *******************************************
	 */
	
	public function toTree($location) {
		return $this->_toTree ( $location );
	}
	
	/*
	 * ********************************************************
	 * Internal Function to retrieve tree of given location
	 * ********************************************************
	 */
	
	private function _toTree($location) {
		if ($location == '') {
			throw new Exception ( 'Invalid Location Provided.' );
		}
		$location_id = '';
		if ($location instanceof Model_Locations) {
			$location_id = $location->getLocation_id ();
		} else {
			$location_id = $location;
		}
		$item = $this->getByID ( $location );
		$item = $item->toArray ();
		if ($this->hasChildrens ( $location )) {
			$subs = $this->_getChildrens ( $location, true );
			foreach ( $subs as $cat ) {
				$item ['child'] [] = $this->_toTree ( $cat ['location_id'] );
			}
		
		}
		
		return $item;
	
	}
	
	/*
	 * **********************************************************
	 * Retrieves the tree from the category to root category
	 * **********************************************************
	 */
	
	public function toRoot($location) {
		if ($location == '') {
			throw new Exception ( 'Invalid Category Provided.' );
		}
		$location_id = '';
		if ($location instanceof Model_Locations) {
			$location_id = $location->getLocation_id ();
		} else {
			$location_id = $location;
		}
		
		$result = $this->getByID ( $location_id );
		$tree = array ();
		
		if ($result) {
			$tree [] = $result;
			while ( $result->getParent_id () > 0 ) {
				$result = $this->getByID ( $result->getParent_id () );
				$tree [] = $result;
			}
		}
		
		return $tree;
	}
	
	/*
	 * ********************************************
	 * Retrieves only root category 
	 * ********************************************
	 */
	
	public function getRoot($location) {
		if ($location == '') {
			throw new Exception ( 'Invalid Category Provided.' );
		}
		$location_id = '';
		if ($location instanceof Model_Locations) {
			$location_id = $location->getLocation_id ();
		} else {
			$location_id = $location;
		}
		
		$result = $this->getByID ( $location_id );
		
		if ($result) {
			while ( $result->getParent_id () > 0 ) {
				$result = $this->getByID ( $result->getParent_id () );
			}
		}
		if ($result) {
			return $result;
		}
		return array ();
	}
	
	public function getItems($location) {
		if ($location == '') {
			throw new Exception ( 'Invalid Location Provided.' );
		}
		$childrens = array ();
		if (! $location instanceof Model_Locations) {
			$location = Model_Mapper_Locations::newInstance ()->getByID ( $location );
		}
		$childrens = $location->getChildrens ( true );
		$items = array ();
		$items [] = $location->getLocation_id ();
		foreach ( $childrens as $child ) {
			$items [] = $child ['location_id'];
		}
		
		$args = array ('location_id' => $items );
		$args ['active'] = 1;
		return Model_Mapper_Items::newInstance ()->getByCondition ( $args );
	
	}
	
	public function getItemCount($location) {
		if ($location == '') {
			throw new Exception ( 'Invalid Location Provided.' );
		}
		if (! $location instanceof Model_Locations) {
			$location = Model_Mapper_Locations::newInstance ()->getByID ( $location );
		}
		$items = $this->getItems ( $location );
		return count ( $items );
	
	}
	
	public function save(Model_Locations $locations) {
		$data = array ('name' => $locations->getName (), 'parent_id' => $locations->getParent_id (), 'slug' => $locations->getSlug (), 'enabled' => $locations->getEnabled () );
		$key = $this->getDbTable ()->getPrimaryKey ();
		$method = 'get' . ucfirst ( $key );
		$val = $categories->$method ();
		if ($val == null) {
			unset ( $data [$key] );
			$this->getDbTable ()->insert ( $data );
		} else {
			$this->getDbTable ()->update ( $data, array ($key . ' = ?' => $val ) );
		}
	}
	
	private function extend($args) {
		$items = array ();
		foreach ( $args as $arg ) {
			$arg = $arg->toArray ();
			$item = new Model_Locations ( $arg );
			$items [] = $item;
		}
		return $items;
	}
	
	public function _extend($args) {
		$items = array ();
		foreach ( $args as $arg ) {
			$item = new Model_Locations ( $arg );
			$items [] = $item;
		}
		return $items;
	}
	
	public function lastInsertID() {
		return $this->getDbTable ()->getAdapter ()->lastInsertId ();
	}
	
	public function beginTransaction() {
		$this->getDbTable ()->getAdapter ()->beginTransaction ();
	}
	
	public function commit() {
		$this->getDbTable ()->getAdapter ()->commit ();
	}
	
	public function rollBack() {
		$this->getDbTable ()->getAdapter ()->rollBack ();
	}
	
	public function getAll($enabled = false) {
		$table = $this->getDbTable ();
		$select = $table->select ();
		$select->from ( $this->getDbTable () );
		if ($enabled) {
			$select->where ( 'enabled=?', 1 );
		}
		
		return $this->extend ( $table->fetchAll ( $select ) );
	}
	
	public function getByID($id) {
		if ($id == '') {
			throw new Exception ( 'Invalid ID Provided.' );
		}
		
		if ($id instanceof Model_Locations) {
			$id = $id->getLocation_id ();
		}
		
		$table = $this->getDbTable ();
		$select = $table->select ();
		$select->where ( $this->getDbTable ()->getPrimaryKey () . '=?', $id );
		$select->from ( $this->getDbTable () );
		$result = $this->extend ( $table->fetchAll ( $select ) );
		return $result [0];
	}

}